﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Win32API;

namespace Forms
{
    public partial class GdiForm : Form
    {
        public event PaintEventHandler Draw;
        public new Rectangle Bounds
        {
            get { return base.Bounds; }
            set {
                base.Bounds = value;
                Invalidate();
            }
        }
        public GdiForm()
        {
            this.FormBorderStyle = FormBorderStyle.None;
        }

        protected override CreateParams CreateParams
        {
            get
            {
                if (this.DesignMode) return base.CreateParams;
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x00080000;
                return cp;
            } 
        }
         
        public override void Refresh()
        {
            Bitmap bmp = new Bitmap(Bounds.Width, Bounds.Height);
            Graphics g = Graphics.FromImage(bmp);
            OnDraw(g);
            g.Dispose();
            DrawBitmap(bmp);
        }

        public new void Invalidate()
        {
            Refresh();
        }

        private void DrawBitmap(Bitmap bitmap)
        {
            if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) return;

            IntPtr screenDc = WinAPI.GetDC(IntPtr.Zero);
            IntPtr memDc = WinAPI.CreateCompatibleDC(screenDc);
            IntPtr hBitmap = IntPtr.Zero;
            IntPtr oldBitmap = IntPtr.Zero;

            try
            {
                hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
                oldBitmap = WinAPI.SelectObject(memDc, hBitmap);
                SIZE size = new SIZE { cx = Bounds.Width, cy = Bounds.Height };
                POINT pointSource = new POINT { x = 0, y = 0 };
                POINT topPos = new POINT { x = Bounds.X, y = Bounds.Y };
                BLENDFUNCTION blend = new BLENDFUNCTION();
                blend.BlendOp = (byte)AlphaFlags.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = 255;
                blend.AlphaFormat = (byte)AlphaFlags.AC_SRC_ALPHA;
                WinAPI.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, (int)UpdateLayeredWindowsFlags.ULW_ALPHA);
            }
            finally
            {
                WinAPI.ReleaseDC(IntPtr.Zero, screenDc);
                if (hBitmap != IntPtr.Zero)
                {
                    WinAPI.SelectObject(memDc, oldBitmap);
                    WinAPI.DeleteObject(hBitmap);
                }
                WinAPI.DeleteDC(memDc);
            }
            bitmap.Dispose();
        }

        protected virtual void OnDraw(Graphics g)
        {
            PaintEventArgs e = new PaintEventArgs(g, Bounds);
            if (Draw != null)
            {
                Draw(this, e);
            }
        }
    }
     
}
